home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pico / os_dos.c < prev    next >
C/C++ Source or Header  |  1996-03-14  |  14KB  |  619 lines

  1. /*
  2.  * $Id: os_dos.c,v 4.38 1996/03/15 07:41:11 hubert Exp $
  3.  *
  4.  * Program:    Operating system dependent routines - MS DOS
  5.  *
  6.  *
  7.  * Michael Seibel
  8.  * Networks and Distributed Computing
  9.  * Computing and Communications
  10.  * University of Washington
  11.  * Administration Builiding, AG-44
  12.  * Seattle, Washington, 98195, USA
  13.  * Internet: mikes@cac.washington.edu
  14.  *
  15.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  16.  *
  17.  *
  18.  * Pine and Pico are registered trademarks of the University of Washington.
  19.  * No commercial use of these trademarks may be made without prior written
  20.  * permission of the University of Washington.
  21.  * 
  22.  * Pine, Pico, and Pilot software and its included text are Copyright
  23.  * 1989-1996 by the University of Washington.
  24.  * 
  25.  * The full text of our legal notices is contained in the file called
  26.  * CPYRIGHT, included with this distribution.
  27.  *
  28.  *
  29.  * Notes:
  30.  *      - mouse support added (mss, 921215)
  31.  *
  32.  *  Portions of this code derived from MicroEMACS 3.10:
  33.  *
  34.  *    MSDOS.C:    Operating specific I/O and Spawning functions
  35.  *            under the MS/PCDOS operating system
  36.  *            for MicroEMACS 3.10
  37.  *            (C)opyright 1988 by Daniel M. Lawrence
  38.  *
  39.  */
  40.  
  41. #include     <stdio.h>
  42. #include    <errno.h>
  43. #include    <setjmp.h>
  44. #include    <time.h>
  45. #include    <fcntl.h>
  46. #include    <io.h>
  47. #include    <bios.h>
  48.  
  49. #include    "osdep.h"
  50. #include        "pico.h"
  51. #include    "estruct.h"
  52. #include        "edef.h"
  53. #include        "dos_gen.h"
  54.  
  55.  
  56. /*
  57.  * Internal functions...
  58.  */
  59. int   enhanced_keybrd(void);
  60. int   dont_interrupt(void);
  61. int   interrupt_ok(void);
  62. int   kbseq(int *);
  63. int   specialkey(unsigned int);
  64. char *pfnexpand(char *, int);
  65. int   ssleep(long);
  66. int   sleep(int);
  67.  
  68.  
  69. /*
  70.  * Useful global def's
  71.  */
  72. int timeout = 0;
  73. static int    enhncd = 0;        /* keyboard of enhanced variety? */
  74. union  REGS   rg;
  75. struct SREGS  segreg;
  76.  
  77. static    int oldbut;            /* Previous state of mouse buttons */
  78. static    unsigned short oldbreak;    /* Original state of break key */
  79. static    char ptmpfile[128];        /* popen temp file */
  80.  
  81.  
  82. /*
  83.  * Include generic DOS/Windows routines
  84.  */
  85. #include    "dos_gen.c"
  86.  
  87.  
  88. /*
  89.  * DISable ctrl-break interruption
  90.  */
  91. dont_interrupt()
  92. {
  93.     /* get original value, to be restored later... */
  94.     rg.h.ah = 0x33;        /* control-break check dos call */
  95.     rg.h.al = 0;        /* get the current state */
  96.     rg.h.dl = 0;        /* pre-set it OFF */
  97.     intdos(&rg, &rg);        /* go for it! */
  98.     oldbreak = rg.h.dl;
  99.     /* kill the ctrl-break interupt */
  100.     rg.h.ah = 0x33;        /* control-break check dos call */
  101.     rg.h.al = 1;        /* set the current state */
  102.     rg.h.dl = 0;        /* set it OFF */
  103.     intdos(&rg, &rg);        /* go for it! */
  104. }
  105.  
  106.  
  107. /*
  108.  * re-enable ctrl-break interruption
  109.  */
  110. interrupt_ok()
  111. {
  112.     /* restore the ctrl-break interupt */
  113.     rg.h.ah = 0x33;        /* control-break check dos call */
  114.     rg.h.al = 1;        /* set to new state */
  115.     rg.h.dl = oldbreak;        /* set it to its original value */
  116.     intdos(&rg, &rg);    /* go for it! */
  117. }
  118.  
  119.  
  120. /*
  121.  * return true if an enhanced keyboard is present
  122.  */
  123. enhanced_keybrd()
  124. {
  125.     /* and check for extended keyboard */
  126.     rg.h.ah = 0x05;
  127.     rg.x.cx = 0xffff;
  128.     int86(BIOS_KEYBRD, &rg, &rg);
  129.     rg.h.ah = 0x10;
  130.     int86(BIOS_KEYBRD, &rg, &rg);
  131.     return(rg.x.ax == 0xffff);
  132. }
  133.  
  134.  
  135. /*
  136.  * This function is called once to set up the terminal device streams.
  137.  */
  138. ttopen()
  139. {
  140.     dont_interrupt();            /* don't allow interrupt */
  141.     enhncd = enhanced_keybrd();        /* check for extra keys */
  142. #if    MOUSE
  143.     init_mouse();
  144. #else    /* !MOUSE */
  145.     mexist = 0;
  146. #endif    /* MOUSE */
  147.     return(1);
  148. }
  149.  
  150.  
  151. /*
  152.  * ttresize - recompute the screen dimensions if necessary, and then
  153.  *          adjust pico's internal buffers accordingly
  154.  */
  155. int
  156. ttresize ()
  157. {
  158.     return (0);            /* no op */
  159. }
  160.  
  161.  
  162. #ifdef    MOUSE
  163. /* 
  164.  * init_mouse - check for and initialize mouse driver...
  165.  */
  166. init_mouse()
  167. {
  168.     long miaddr;        /* mouse interupt routine address */
  169.  
  170.     if(mexist)
  171.       return(TRUE);
  172.  
  173.     /* check if the mouse drive exists first */
  174.     rg.x.ax = 0x3533;        /* look at the interrupt 33 address */
  175.     intdosx(&rg, &rg, &segreg);
  176.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  177.     if (miaddr == 0 || *(char *)miaddr == 0xcf) {
  178.     mexist = FALSE;
  179.     return(TRUE);
  180.     }
  181.  
  182.     /* and then check for the mouse itself */
  183.     rg.x.ax = 0;            /* mouse status flag */
  184.     int86(BIOS_MOUSE, &rg, &rg);    /* check for the mouse interupt */
  185.     mexist = (rg.x.ax != 0);
  186.     nbuttons = rg.x.bx;
  187.  
  188.     if (mexist == FALSE)
  189.     return(TRUE);
  190.  
  191.     /* if the mouse exists.. get it in the upper right corner */
  192.     rg.x.ax = 4;            /* set mouse cursor position */
  193.     rg.x.cx = (term.t_ncol/2) << 3;    /* Center of display... */
  194.     rg.x.dx = 1 << 3;            /* Second line down */
  195.     int86(BIOS_MOUSE, &rg, &rg);
  196.  
  197.     /* and set its attributes */
  198.     rg.x.ax = 10;        /* set text cursor */
  199.     rg.x.bx = 0;        /* software text cursor please */
  200.     rg.x.cx = 0x77ff;    /* screen mask */
  201.     rg.x.dx = 0x7700;    /* cursor mask */
  202.     int86(BIOS_MOUSE, &rg, &rg);
  203.     return(TRUE);
  204. }
  205.  
  206.  
  207. /*
  208.  * mouseon - call made available for programs calling pico to turn ON the
  209.  *           mouse cursor.
  210.  */
  211. void
  212. mouseon()
  213. {
  214.     rg.x.ax = 1;            /* Show Cursor */
  215.     int86(BIOS_MOUSE, &rg, &rg); 
  216. }
  217.  
  218.  
  219. /*
  220.  * mouseon - call made available for programs calling pico to turn OFF the
  221.  *           mouse cursor.
  222.  */
  223. void
  224. mouseoff()
  225. {
  226.     rg.x.ax = 2;            /* Hide Cursor */
  227.     int86(BIOS_MOUSE, &rg, &rg);
  228. }
  229. #endif
  230.  
  231.  
  232. /*
  233.  * This function gets called just before we go back home to the command
  234.  * interpreter.
  235.  */
  236. ttclose()
  237. {
  238.     if(!Pmaster)
  239.       interrupt_ok();
  240.  
  241.     return(1);
  242. }
  243.  
  244.  
  245. /*
  246.  * Flush terminal buffer. Does real work where the terminal output is buffered
  247.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  248.  */
  249. ttflush()
  250. {
  251.     return(1);
  252. }
  253.  
  254.  
  255. /*
  256.  * specialkey - return special key definition
  257.  */
  258. specialkey(kc)
  259. unsigned  kc;
  260. {
  261.     switch(kc){
  262.     case 0x3b00 : return(F1);
  263.     case 0x3c00 : return(F2);
  264.     case 0x3d00 : return(F3);
  265.     case 0x3e00 : return(F4);
  266.     case 0x3f00 : return(F5);
  267.     case 0x4000 : return(F6);
  268.     case 0x4100 : return(F7);
  269.     case 0x4200 : return(F8);
  270.     case 0x4300 : return(F9);
  271.     case 0x4400 : return(F10);
  272.     case 0x8500 : return(F11);
  273.     case 0x8600 : return(F12);
  274.     case 0x4800 : return(K_PAD_UP);
  275.     case 0x5000 : return(K_PAD_DOWN);
  276.     case 0x4b00 : return(K_PAD_LEFT);
  277.     case 0x4d00 : return(K_PAD_RIGHT);
  278.     case 0x4700 : return(K_PAD_HOME);
  279.     case 0x4f00 : return(K_PAD_END);
  280.     case 0x4900 : return(K_PAD_PREVPAGE);
  281.     case 0x5100 : return(K_PAD_NEXTPAGE);
  282.     case 0x5300 : return(K_PAD_DELETE);
  283.     case 0x48e0 : return(K_PAD_UP);            /* grey key version */
  284.     case 0x50e0 : return(K_PAD_DOWN);        /* grey key version */
  285.     case 0x4be0 : return(K_PAD_LEFT);        /* grey key version */
  286.     case 0x4de0 : return(K_PAD_RIGHT);        /* grey key version */
  287.     case 0x47e0 : return(K_PAD_HOME);        /* grey key version */
  288.     case 0x4fe0 : return(K_PAD_END);        /* grey key version */
  289.     case 0x49e0 : return(K_PAD_PREVPAGE);        /* grey key version */
  290.     case 0x51e0 : return(K_PAD_NEXTPAGE);        /* grey key version */
  291.     case 0x53e0 : return(K_PAD_DELETE);        /* grey key version */
  292.     default     : return(NODATA);
  293.     }
  294. }
  295.  
  296.  
  297. /*
  298.  * Read a character from the terminal, performing no editing and doing no echo
  299.  * at all. Also mouse events are forced into the input stream here.
  300.  */
  301. ttgetc()
  302. {
  303.     return(_bios_keybrd(enhncd ? _NKEYBRD_READ : _KEYBRD_READ));
  304. }
  305.  
  306.  
  307. /*
  308.  * ctrlkey - used to check if the key hit was a control key.
  309.  */
  310. ctrlkey()
  311. {
  312.     return(_bios_keybrd(enhncd ? _NKEYBRD_SHIFTSTATUS : _KEYBRD_SHIFTSTATUS)
  313.             & 0x04);
  314. }
  315.  
  316.  
  317. /*
  318.  * win_multiplex - give DOS in a window a shot at the CPU
  319.  */
  320. win_multiplex()
  321. {
  322.     rg.x.ax = 0x1680;
  323.     int86(DOS_MULTIPLEX, &rg, &rg);
  324. }
  325.  
  326.  
  327. /*
  328.  * Read in a key.
  329.  * Do the standard keyboard preprocessing. Convert the keys to the internal
  330.  * character set.  Resolves escape sequences and returns no-op if global
  331.  * timeout value exceeded.
  332.  */
  333. GetKey()
  334. {
  335.     unsigned ch = 0, lch, intrupt = 0;
  336.     long timein;
  337.  
  338.     if(mexist || timeout){
  339.     timein = time(0L);
  340. #ifdef    MOUSE
  341.     if(mexist){
  342.         rg.x.ax = 1;            /* Show Cursor */
  343.         int86(BIOS_MOUSE, &rg, &rg); 
  344.     }
  345. #endif
  346.     while(!_bios_keybrd(enhncd ? _NKEYBRD_READY : _KEYBRD_READY)){
  347. #if    MOUSE
  348.         if(timeout && time(0L) >= timein+timeout){
  349.         if(mexist){
  350.             rg.x.ax = 2;        /* Hide Cursor */
  351.             int86(BIOS_MOUSE, &rg, &rg);
  352.         }
  353.         return(NODATA);
  354.         }
  355.  
  356.         if(checkmouse(&ch,0,0,0)){        /* something happen ?? */
  357.         if(mexist){
  358.             rg.x.ax = 2;        /* Hide Cursor */
  359.             int86(BIOS_MOUSE, &rg, &rg);
  360.         }
  361.         curwp->w_flag |= WFHARD;
  362.         return(ch);
  363.         }
  364. #else
  365.         if(time(0L) >= timein+timeout)
  366.           return(NODATA);
  367. #endif    /* MOUSE */
  368.  
  369.         /*
  370.          * Surrender the CPU...
  371.          */
  372.         if(!intrupt++)
  373.           win_multiplex();
  374.         }
  375. #ifdef    MOUSE
  376.     if(mexist){
  377.         rg.x.ax = 2;            /* Hide Cursor */
  378.         int86(BIOS_MOUSE, &rg, &rg);
  379.     }
  380. #endif    /* MOUSE */
  381.     }
  382.  
  383.     ch  = (*term.t_getchar)();
  384.     lch = (ch&0xff);
  385.     return((lch && (lch != 0xe0 || !(ch & 0xff00))) 
  386.             ? (lch < ' ') ? (CTRL|(lch + '@')) 
  387.                           : (lch == ' ' && ctrlkey()) ? (CTRL|'@') : lch
  388.             : specialkey(ch));
  389. }
  390.  
  391.  
  392. #if    MOUSE
  393. /* 
  394.  * checkmouse - look for mouse events in key menu and return 
  395.  *              appropriate value.
  396.  *   NOTE: "down", "xxx", and "yyy" aren't used under DOS.
  397.  */
  398. int
  399. checkmouse(ch, down, xxx, yyy)
  400. unsigned *ch;
  401. int      down, xxx, yyy;
  402. {
  403.     register int k;        /* current bit/button of mouse */
  404.     int mcol;            /* current mouse column */
  405.     int mrow;            /* current mouse row */
  406.     int sstate;            /* current shift key status */
  407.     int newbut;            /* new state of the mouse buttons */
  408.     int button;
  409.     int rv = 0;
  410.  
  411.     if(!mexist)
  412.     return(FALSE);
  413.  
  414.     /* check to see if any mouse buttons are different */
  415.     rg.x.ax = 3;        /* Get button status and mouse position */
  416.     int86(BIOS_MOUSE, &rg, &rg);
  417.     newbut = rg.x.bx;
  418.     mcol = rg.x.cx >> 3;
  419.     mrow = (rg.x.dx >> 3);
  420.  
  421.     /* only notice changes */
  422.     if (oldbut == newbut)
  423.     return(FALSE);
  424.  
  425.     if (mcol < 0)        /* only on screen presses are legit! */
  426.     mcol = 0;
  427.     if (mrow < 0)
  428.     mrow = 0;
  429.  
  430.     sstate = 0;            /* get the shift key status as well */
  431.     rg.h.ah = 2;
  432.     int86(BIOS_KEYBRD, &rg, &rg);
  433.     sstate = rg.h.al;
  434.  
  435.     button = M_BUTTON_LEFT;
  436.     for (k=1; k != (1 << nbuttons); k = k<<1) {
  437.     /* For each button on the mouse */
  438.     if ((oldbut&k) != (newbut&k)) {
  439.         if(k == 1){
  440.         static int oindex;
  441.         int i = 0;
  442.         MENUITEM *mp;
  443.  
  444.         if(newbut&k)            /* button down */
  445.           oindex = -1;
  446.  
  447.         for(mp = mfunc; mp; mp = mp->next)
  448.           if(mp->action && M_ACTIVE(mrow, mcol, mp))
  449.             break;
  450.  
  451.         if(mp){
  452.             unsigned long r;
  453.  
  454.             r = (*mp->action)((newbut&k) ? M_EVENT_DOWN : M_EVENT_UP,
  455.                       mrow, mcol, button, 0);
  456.             if(r & 0xffff){
  457.             *ch = (unsigned)((r>>16)&0xffff);
  458.             rv  = TRUE;
  459.             }
  460.         }
  461.         else{
  462.             while(1){    /* see if we understand event */
  463.             if(i >= 12){
  464.                 i = -1;
  465.                 break;
  466.             }
  467.  
  468.             if(M_ACTIVE(mrow, mcol, &menuitems[i]))
  469.               break;
  470.  
  471.             i++;
  472.             }
  473.  
  474.             if(newbut&k){            /* button down */
  475.             oindex = i;            /* remember where */
  476.             if(i != -1)            /* invert label */
  477.               invert_label(1, &menuitems[i]);
  478.             }
  479.             else{                /* button up */
  480.             if(oindex != -1){
  481.                 if(i == oindex){
  482.                 *ch = menuitems[i].val;
  483.                 rv = 1;
  484.                 }
  485.             }
  486.             }
  487.         }
  488.  
  489.         if(!(newbut&k) && oindex != -1)
  490.           invert_label(0, &menuitems[oindex]);    /* restore label */
  491.         }
  492.  
  493.         oldbut = newbut;
  494.         return(rv);
  495.     }
  496.  
  497.     ++button;
  498.     }
  499.  
  500.     return(FALSE);
  501. }
  502.  
  503.  
  504. /*
  505.  * invert_label - highlight the label of the given menu item.
  506.  */
  507. void
  508. invert_label(state, m)
  509. int state;
  510. MENUITEM *m;
  511. {
  512.     int i, j, r, c, p, col_offset;
  513.     char *lp;
  514.     int old_state = getrevstate();
  515.  
  516.     if(m->val == mnoop)
  517.       return;
  518.  
  519.     rg.h.ah = 3;                /* get cursor position */
  520.     int86(BIOS_VIDEO, &rg, &rg);
  521.     p = rg.h.bh;
  522.     c = rg.h.dl;
  523.     r = rg.h.dh;
  524.     rg.x.ax = 2;                /* Hide Cursor */
  525.     int86(BIOS_MOUSE, &rg, &rg);
  526.     /*
  527.      * Leave the command name bold
  528.      */
  529.     col_offset = (state || !(lp=strchr(m->label, ' '))) ? 0 : (lp - m->label);
  530.     (*term.t_move)(m->tl.r, m->tl.c + col_offset);
  531.     (*term.t_rev)(state);
  532.     for(i = m->tl.r; i <= m->br.r; i++)
  533.       for(j = m->tl.c + col_offset; j <= m->br.c; j++)
  534.     if(i == m->lbl.r && j == m->lbl.c + col_offset){ /* show label?? */
  535.         lp = m->label + col_offset;
  536.         while(*lp && j++ < m->br.c)
  537.           (*term.t_putchar)(*lp++);
  538.  
  539.         continue;
  540.     }
  541.     else
  542.       (*term.t_putchar)(' ');
  543.  
  544.     (*term.t_rev)(old_state);
  545.     rg.h.ah = 2;
  546.     rg.h.bh = p;
  547.     rg.h.dh = r;
  548.     rg.h.dl = c;
  549.     int86(BIOS_VIDEO, &rg, &rg);        /* restore old position */
  550.     rg.x.ax = 1;                /* Show Cursor */
  551.     int86(BIOS_MOUSE, &rg, &rg);
  552. }
  553. #endif    /* MOUSE */
  554.  
  555.  
  556. /*
  557.  * alt_editor - fork off an alternate editor for mail message composition
  558.  *
  559.  *  NOTE: Not yet used under DOS
  560.  */
  561. alt_editor(f, n)
  562. {
  563.     return(-1);
  564. }
  565.  
  566.  
  567. /*
  568.  *  bktoshell - suspend and wait to be woken up
  569.  */
  570. bktoshell()        /* suspend MicroEMACS and wait to wake up */
  571. {
  572.     int i;
  573.     char *shell;
  574.  
  575.     (*term.t_move)(term.t_nrow, 0);
  576.     if(system((shell = getenv("COMSPEC")) ? shell : "command") == -1)
  577.       emlwrite("Error loading %s", shell ? shell : "COMMAND.COM");
  578.     else
  579.       refresh(0, 1);            /* redraw */
  580. }
  581.  
  582.  
  583. /*
  584.  * P_open - run the given command in a sub-shell returning a file pointer
  585.  *        from which to read the output
  586.  *
  587.  * note:
  588.  *    For OS's other than unix, you will have to rewrite this function.
  589.  *    Hopefully it'll be easy to exec the command into a temporary file, 
  590.  *    and return a file pointer to that opened file or something.
  591.  */
  592. FILE *P_open(c)
  593. char *c;
  594. {
  595.     char cmdbuf[NLINE];
  596.     sprintf(ptmpfile, tmpnam(NULL));
  597.     sprintf(cmdbuf, "%s > %s", c, ptmpfile);
  598.     if(system(cmdbuf) == -1){
  599.     unlink(ptmpfile);
  600.     return(NULL);
  601.     }
  602.  
  603.     return(fopen(ptmpfile, "r"));
  604. }
  605.  
  606.  
  607.  
  608. /*
  609.  * P_close - close the given descriptor
  610.  *
  611.  */
  612. P_close(fp)
  613. FILE *fp;
  614. {
  615.     fclose(fp);            /* doesn't handle return codes */
  616.     unlink(ptmpfile);
  617.     return(0);;
  618. }
  619.